/**
 * 
 */
package idv.takeshi.software.productline.bookstore.presentation.web.controller;

import idv.takeshi.software.productline.bookstore.application.service.MaintainOrdersService;
import idv.takeshi.software.productline.bookstore.application.service.dto.AtmPaymentDto;
import idv.takeshi.software.productline.bookstore.application.service.dto.MultiUserAccountDto;
import idv.takeshi.software.productline.bookstore.application.service.dto.PaymentDto;
import idv.takeshi.software.productline.bookstore.application.service.dto.PostalOrderPaymentDto;
import idv.takeshi.software.productline.bookstore.domain.model.order.Atm;
import idv.takeshi.software.productline.bookstore.domain.model.order.Order;
import idv.takeshi.software.productline.bookstore.domain.model.order.OrderStatus;
import idv.takeshi.software.productline.bookstore.domain.model.order.OrderStatusToUnderProcessingException;
import idv.takeshi.software.productline.bookstore.domain.model.order.PostalOrder;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.UserAccount;
import idv.takeshi.software.productline.bookstore.utils.text.ServletPathStringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * A Controller for maintaining user orders operations.
 * @author takeshi
 *
 */
@Controller("maintainOrdersController")
@RequestMapping(value = "/orders")
public class MaintainOrdersController {
	
	private static final String PAYMENT_DTO_NAME = "paymentDto";

	private static final Log log = LogFactory.getLog(MaintainOrdersController.class);
	
	private static final String[] DATE_PATTERNS = new String[]{"yy-MM-dd", "yyyy-MM-dd"};
	
	@Autowired
	private MaintainOrdersService MaintainOrdersService;
	
	@Autowired
	private MessageSource messageSource;
	
	@RequestMapping(value = "/listOrders.html", method = RequestMethod.GET)
	public void listOrders(
			@RequestParam(required = false) String userAccountName, 
			@RequestParam(required = false) String recipientName, 
			@RequestParam(required = false) String orderStatus,
			@RequestParam(required = false) String fromUpdateTime, 
			@RequestParam(required = false) String toUpdateTime, 
			@RequestParam(required = false) String fromCreateTime, 
			@RequestParam(required = false) String toCreateTime,
			@RequestParam(required = false) BigDecimal fromPrice, 
			@RequestParam(required = false) BigDecimal toPrice, 
			ModelMap modelMap, HttpServletRequest request) {
		
		Set<Order> orders = null;
		try {
			Date tmpFromUpdateTime = StringUtils.isNotBlank(fromUpdateTime)? 
					DateUtils.parseDate(fromUpdateTime, DATE_PATTERNS): null;
			Date tmpToUpdateTime = StringUtils.isNotBlank(toUpdateTime)? 
					DateUtils.parseDate(toUpdateTime, DATE_PATTERNS): null;
			Date tmpFromCreateTime = StringUtils.isNotBlank(fromCreateTime)? 
					DateUtils.parseDate(fromCreateTime, DATE_PATTERNS): null;
			Date tmpToCreateTime = StringUtils.isNotBlank(toCreateTime)? 
					DateUtils.parseDate(toCreateTime, DATE_PATTERNS): null;
			OrderStatus tmpOrderStatus = null;
			try{
				tmpOrderStatus = StringUtils.isNotBlank(orderStatus)? OrderStatus.valueOf(orderStatus): null;
			} catch(IllegalArgumentException e){}
			orders = this.MaintainOrdersService.getOrders(userAccountName, recipientName, tmpOrderStatus, 
					tmpFromUpdateTime, tmpToUpdateTime, tmpFromCreateTime, tmpToCreateTime, 
					fromPrice, toPrice);
		} catch (ParseException e) {
			String msg = "parse date error";
			log.error(msg, e);
		} 
		modelMap.addAttribute("orders", orders);
		modelMap.addAttribute("orderStatuses", OrderStatus.values());
		
		String currentPath = request.getServletPath();
		currentPath += StringUtils.isNotBlank(request.getQueryString())? "?" + request.getQueryString(): ""; 
		modelMap.addAttribute("currentPath", currentPath);
	}
	
	@RequestMapping(value = "/maintainOrder.html", method = RequestMethod.GET)
	public void maintainOrder(@RequestParam Long orderId, ModelMap modelMap, HttpServletRequest request){
		UserAccount userAccount = null;
		Order order = null;
		
		userAccount = this.MaintainOrdersService.getUserAccountByOrderId(orderId);
		order = this.MaintainOrdersService.getOrderById(orderId);
		
		modelMap.addAttribute("userAccount", userAccount);
		modelMap.addAttribute("order", order);
		
		String currentPath = request.getServletPath();
		currentPath += StringUtils.isNotBlank(request.getQueryString())? "?" + request.getQueryString(): "";
		modelMap.addAttribute("currentPath", currentPath);
	}
	
	@RequestMapping(value = "/maintainAtmPayment.html", method = RequestMethod.GET)
	public void createAtmPaymentDto(
			@RequestParam Long orderId, @RequestParam String previousPath, ModelMap modelMap){
		Order order = null;
		AtmPaymentDto paymentDto = null;
		order = this.MaintainOrdersService.getOrderById(orderId);
		paymentDto = new AtmPaymentDto(order);
		paymentDto.setOrderId(orderId);
		paymentDto.setPreviousPath(previousPath);
		
		modelMap.addAttribute(PAYMENT_DTO_NAME, paymentDto);
	}
	
	@RequestMapping(value = "/maintainAtmPayment.html", method = RequestMethod.POST)
	public String updateAtmPayment(
			@ModelAttribute(PAYMENT_DTO_NAME) @Valid final AtmPaymentDto paymentDto, final BindingResult result, 
			final Locale locale, ModelMap modelMap){
		
		if(result.hasErrors())
			return "/orders/maintainAtmPayment";
		
		this.MaintainOrdersService.updatePayment(paymentDto);
		return "redirect:" + paymentDto.getPreviousPath();
	}
	
	
	@RequestMapping(value = "/maintainPostalOrderPayment.html", method = RequestMethod.GET)
	public void createPostalOrderPaymentDto(
			@RequestParam Long orderId, @RequestParam String previousPath, ModelMap modelMap){
		Order order = null;
		PostalOrderPaymentDto paymentDto = null;
		order = this.MaintainOrdersService.getOrderById(orderId);
		paymentDto = new PostalOrderPaymentDto(order);
		paymentDto.setOrderId(orderId);
		paymentDto.setPreviousPath(previousPath);
		
		modelMap.addAttribute(PAYMENT_DTO_NAME, paymentDto);
	}
	
	@RequestMapping(value = "/maintainPostalOrderPayment.html", method = RequestMethod.POST)
	public String updatePostalOrderPayment(
			@ModelAttribute(PAYMENT_DTO_NAME) @Valid final PostalOrderPaymentDto paymentDto, final BindingResult result, 
			final Locale locale, ModelMap modelMap){
		
		if(result.hasErrors())
			return "/orders/maintainPostalOrderPayment";
		
		this.MaintainOrdersService.updatePayment(paymentDto);
		return "redirect:" + paymentDto.getPreviousPath();
	}
	
	@RequestMapping(value = "/maintainCashInConvinientStorePayment.html", method = RequestMethod.GET)
	public void createPaymentDto(
			@RequestParam Long orderId, @RequestParam String previousPath, ModelMap modelMap){
		Order order = null;
		PaymentDto paymentDto = null;
		order = this.MaintainOrdersService.getOrderById(orderId);
		paymentDto = new PaymentDto(order);
		paymentDto.setOrderId(orderId);
		paymentDto.setPreviousPath(previousPath);
		
		modelMap.addAttribute(PAYMENT_DTO_NAME, paymentDto);
	}
	
	@RequestMapping(value = "/maintainCashInConvinientStorePayment.html", method = RequestMethod.POST)
	public String updatePayment(
			@ModelAttribute(PAYMENT_DTO_NAME) @Valid final PaymentDto paymentDto, final BindingResult result, 
			final Locale locale, ModelMap modelMap){
		
		if(result.hasErrors())
			return "/orders/maintainCashInConvinientStorePayment";
		
		this.MaintainOrdersService.updatePayment(paymentDto);
		return "redirect:" + paymentDto.getPreviousPath();
	}
	
	@RequestMapping(value = "/nextStatus.html", method = RequestMethod.GET)
	public String goToNextStatus(
			@RequestParam Long orderId, @RequestParam String methodName, @RequestParam String previousPath,
			Locale locale){
		String errorMsg = null;
		String nextPath = previousPath;
		
		try {
			this.MaintainOrdersService.goToNextStatus(orderId, methodName);
		} catch (OrderStatusToUnderProcessingException e) {
			errorMsg = messageSource.getMessage(
					"orders.maintainOrders.order.status.processing.notPaid", null, locale);
			
			nextPath += nextPath.indexOf("?") > -1? "&errorMsg=" + errorMsg: "?errorMsg=" + errorMsg;
		}
		
		if(StringUtils.isBlank(errorMsg)){
			nextPath = ServletPathStringUtils.removeQueryStringParameters(nextPath, "errorMsg");
		}
		
		return "redirect:" + nextPath;
	}
	
	@RequestMapping(value = "/cancelOrder.html", method = RequestMethod.GET)
	public String cancelOrder(
			@RequestParam Long orderId, @RequestParam String previousPath){
		
		this.MaintainOrdersService.cancelOrder(orderId);
		return "redirect:" + previousPath;
	}
	
}
